home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
MacGzip 1.0
/
source
/
Mac
/
MacIO.c
< prev
next >
Wrap
Text File
|
1995-09-28
|
20KB
|
863 lines
/*
* MacIO.c
*
* SPDsoft, August 19, 1995
* A minimal, non standard Mac IO implementation
*
* Secuential read/write, ascii/binary/macbinary, buffered IO
*
* Sept, 1995: Multiple bug fixes.
*/
/*
* open:
* - in MacBinary w mode, actual open is delayed to write/close
* - in MacBinary w mode, if file is not MB, fs is used; otherwise
* MB name is copied to fs;
*
* - In any w mode, output file must not exist
*/
/*
* fd_table[].new is used only externally
* You can safely remove all references
*/
#include <errno.h>
#include <Files.h>
#include <Memory.h>
#include "MacBinary.h"
#include "MacIO.h"
#include "GzErrors.h"
#ifndef MIN
#define MIN(a,b) ( ((a)<(b)) ? (a) : (b) )
#endif
#ifndef PStrCpy
#define PStrCpy(a,b) BlockMove((b), (a), *(b) + 1 )
#endif
OSType DefCreator = 'Gzip';
OSType DefType = '\?\?\?\?';
fildes fd_table[MIO_MAX_FILES];
int fd_busy[MIO_MAX_FILES] = { 0, 0 };
static int fs_MBflush( int fd );
static int MyBlockMove( char *src, char *dst, Size n, char c1, char c2 );
static OSErr OpenPlainFromMB( int fd );
static int CatInfoToStat (CInfoPBRec *info, struct stat *buf);
static void SanitizeName (Str255 name);
/*
* these are in gzip.c You can delete them safely (along with the calls)
* for other applications
*/
extern FSSpec ofs;
extern char ofname[];
extern int decompress;
extern OSErr MakeOFSSpec( FSSpec *fs , Str255 prompt );
extern void SetMMString( const char *fmt, ... );
/* end of gzip options
*/
extern int DoError( int ErrType, int ErrSever,const char *, ...);
/******************************************************************************
* functions
*/
#define ExitErr(a) { if ((a) != noErr ) { errno = (a); return -1; } }
/*
* Upon successful completion, the file descriptor is returned.
* Otherwise, a value of -1 is returned and errno is set to indicate the
* error.
*/
int fs_open( FSSpec *fs, int mode, ...)
{
int i;
OSErr err;
if (( fs == nil )||(mode & OM_RDWR))/* not supported */
{
errno = EFAULT;
return -1;
}
for ( i = 0; i< MIO_MAX_FILES; i++ )
if (fd_busy[i] == 0)
break;
if ( i == MIO_MAX_FILES )
{
errno = ENFILE;
return -1;
}
fd_table[i].fsomode = mode;
fd_table[i].mode = MIO_BINARY;
if ( mode & OM_TEXT ) fd_table[i].mode = MIO_ASCII;
if ( mode & OM_MACBINARY ) fd_table[i].mode = MIO_MACBIN;
if ( mode & OM_WRONLY )
{
fd_table[i].omode = OM_WRONLY;
fd_table[i].dref = 0;
fd_table[i].rref = 0;
fd_table[i].pos = 0L;
fd_table[i].len = 0L;
fd_table[i].blen = 0;
fd_table[i].bstart = fd_table[i].buffer;
fd_table[i].deof = 0;
fd_table[i].reof = 0;
fd_table[i].new = 0;
fd_table[i].fs = *fs;
if (fd_table[i].mode != MIO_MACBIN)
{
err = FSpCreate(fs, DefCreator, DefType, 0);
ExitErr(err);
fd_table[i].new = 1;
if ( noErr != (err = FSpOpenDF(fs, fsWrPerm, &fd_table[i].dref)))
{
fd_table[i].dref = 0;
FSpDelete(fs);
errno = err;
return -1;
}
}
else
{
fd_table[i].bstart = (char *)&fd_table[i].header;
}
/* we can't open nothing in MacBinary Mode */
}
else /* OM_RDONLY */
{
err = MBHeaderFromFSSpec( fs, &fd_table[i].start, (MBIIHeader *) &fd_table[i].buffer);
ExitErr(err);
fd_table[i].omode = OM_RDONLY;
fd_table[i].dref = 0;
fd_table[i].rref = 0;
fd_table[i].pos = 0L;
fd_table[i].len = 0L;
fd_table[i].blen = 0;
fd_table[i].bstart = fd_table[i].buffer;
fd_table[i].deof = 0;
fd_table[i].reof = 0;
fd_table[i].new = 0;
fd_table[i].fs = *fs;
err = FSpOpenDF(fs, fsRdPerm, &fd_table[i].dref);
ExitErr(err);
if (fd_table[i].mode == MIO_MACBIN)
{
fd_table[i].blen = sizeof(MBIIHeader);
fd_table[i].len = sizeof(MBIIHeader) + fd_table[i].start.dlen + fd_table[i].start.rlen;
if ( noErr != (err = FSpOpenRF(fs, fsRdPerm, &fd_table[i].rref)))
{
FSClose(fd_table[i].dref); fd_table[i].dref = fd_table[i].rref = 0;
errno = err;
return -1;
}
}
else
{
fd_table[i].len = fd_table[i].start.dlen;
fd_table[i].start.rlen = 0;
}
}
fd_busy[i] = 1;
return i;
}
int fs_close(int fd)
{
ParamBlockRec pb;
OSErr err = noErr;
long count = 0;
Boolean SetInfo;
if (( 0 > fd ) || ( fd >= MIO_MAX_FILES) || (fd_busy[fd] == 0))
{
errno = EBADF;
return -1;
}
fd_busy[fd] = 0;
if ( fd_table[fd].omode != OM_RDONLY ) /* flush buffer here */
{
if (fd_table[fd].mode == MIO_MACBIN)
{
if (fd_table[fd].pos < 128L ) /* it isn't a MacBinary and is too short */
{
err = OpenPlainFromMB( fd );
}
else
{
err = (OSErr) fs_MBflush( fd );
if ( err > 0 ) err = 0;
ExitErr(err);
if ( fd_table[fd].dref != 0 )
err = SetEOF( fd_table[fd].dref, fd_table[fd].start.dlen );
if (( fd_table[fd].rref != 0 )&&(err==noErr))
err = SetEOF( fd_table[fd].rref, fd_table[fd].start.rlen );
}
}
ExitErr(err);
if (fd_table[fd].mode != MIO_MACBIN)
{
if ( fd_table[fd].blen != 0 )
{
count = (long)fd_table[fd].blen;
err = FSWrite( fd_table[fd].dref, &count, fd_table[fd].buffer );
ExitErr(err);
}
err = SetEOF( fd_table[fd].dref, fd_table[fd].pos ); /* ??? */
}
ExitErr(err);
}
SetInfo = (fd_table[fd].mode == MIO_MACBIN) &&
( fd_table[fd].omode != OM_RDONLY ) &&
( fd_table[fd].dref != 0 ) &&
( fd_table[fd].rref != 0 ) ;
if ( fd_table[fd].dref != 0 )
{
if ( fd_table[fd].omode != OM_RDONLY )
{
pb.ioParam.ioCompletion = 0;
pb.ioParam.ioRefNum = fd_table[fd].dref;
PBFlushFile(&pb,FALSE);
}
err = FSClose(fd_table[fd].dref);
fd_table[fd].dref = 0;
}
if (( fd_table[fd].rref != 0 )&&(err==noErr))
{
if ( fd_table[fd].omode != OM_RDONLY )
{
pb.ioParam.ioCompletion = 0;
pb.ioParam.ioRefNum = fd_table[fd].rref;
PBFlushFile(&pb,FALSE);
}
err = FSClose(fd_table[fd].rref);
fd_table[fd].rref = 0;
}
if (SetInfo)
SetCatInfoFromMBHeader( &fd_table[fd].fs, &fd_table[fd].start, &fd_table[fd].header);
ExitErr(err);
return 0;
}
int fs_unlink(FSSpec *fs)
{
return(FSpDelete(fs));
}
/*
* WARNING: This should be size_t, but it is defined as unsigned!
*
* fs_read should return always >= 0 or -1
* On failure, return -1 and set errno to indicate the error
* We will use mixed errno/OSErr codes (I hope thy will be coherent!)
*/
int fs_read(int fd, char *buf, unsigned int n)
{
OSErr err = noErr;
long count,
round;
int result = 0;
short ref;
if (( 0 > fd ) || ( fd >= MIO_MAX_FILES) || (fd_busy[fd] == 0))
{
errno = EBADF;
return -1;
}
while (( n > 0 ) && (err == noErr))
{
if (fd_table[fd].blen == 0)
{
if ( fd_table[fd].deof == 0 )
{
ref = fd_table[fd].dref;
}
else
{
if ( fd_table[fd].reof == 0 )
{
ref = fd_table[fd].rref;
}
else
{
n = 0;
if (result == 0 ) result = -1;
}
}
if (ref != 0)
{
count = MIO_BUFSIZE;
err = FSRead( ref, &count, fd_table[fd].buffer );
fd_table[fd].blen += (int) count;
fd_table[fd].bstart = fd_table[fd].buffer;
if ( err == eofErr ) /* end of fork reached */
{
if (fd_table[fd].mode == MIO_MACBIN)
if ( 0 != (round = count%128))
{
count += 128L - round;
fd_table[fd].blen += 128 - (int)round;
}
if ( fd_table[fd].deof == 1 )
fd_table[fd].reof = 1;
else
fd_table[fd].deof = 1;
err = noErr;
}
}
else
{
count = 0;
err = eofErr;
}
errno = err;
}
else
{
count = MIN( fd_table[fd].blen, (long) n);
if (fd_table[fd].mode == MIO_ASCII)
MyBlockMove( fd_table[fd].bstart, buf, (Size) count, 0x0d, 0x0a );
else
BlockMove( fd_table[fd].bstart, buf, (Size) count );
buf += count;
fd_table[fd].blen -= (int) count;
fd_table[fd].pos += count;
fd_table[fd].bstart += (int) count;
result += (int) count;
n -= (int) count;
}
}
return result;
}
/*
* Por amor al comercio
* voy a cruzar ese puente
* Por amor al comercio
* voy a cuidar ese dolor
*/
/*
* should return n
* On failure, return -1 and set errno to indicate the error
*
* n == 0 => return 0
*/
int fs_write(int fd, char *buf, unsigned int n)
{
OSErr err = noErr;
long count;
int result = 0;
if (( 0 > fd ) || ( fd >= MIO_MAX_FILES) || (fd_busy[fd] == 0))
{
errno = EBADF;
return -1;
}
if (fd_table[fd].mode == MIO_MACBIN)
{
/* (probably) MacBinary File */
while (( n > 0 ) && (err == noErr))
{
if (fd_table[fd].pos < 128L ) /* fill header struct */
{
count = MIN( (128L - fd_table[fd].pos), (long) n);
BlockMove( buf, fd_table[fd].bstart, (Size) count );
buf += count;
fd_table[fd].pos += count;
fd_table[fd].bstart += (int) count;
result += (int) count;
n -= (int) count;
if (fd_table[fd].pos == 128L )
{
/* validate header */
if (PT_File == ValidateMBHeader( &fd_table[fd].start, &fd_table[fd].header, true ))
{
PStrCpy( fd_table[fd].fs.name, fd_table[fd].start.name );
SanitizeName (fd_table[fd].fs.name);
/* macgzip -> */
if ( decompress && ( ( fd_table[fd].start.rlen != 0 ) || ( fd_table[fd].start.dlen != 0 )))
{
err = MakeOFSSpec( &fd_table[fd].fs , "\pSave Macintosh File:" );
ofs = fd_table[fd].fs;
ExitErr(err); /* OJO */
}
/* <- macgzip */
if ( fd_table[fd].start.dlen == 0 )
{
fd_table[fd].dref = 0;
fd_table[fd].deof = 1;
}
else
{
if ( noErr == ( err =
FSpCreate( &fd_table[fd].fs, fd_table[fd].start.fcreator, fd_table[fd].start.ftype, 0)))
{
fd_table[fd].new = 1;
err = FSpOpenDF( &fd_table[fd].fs, fsWrPerm, &fd_table[fd].dref);
}
ExitErr(err);
if ( 0 != (fd_table[fd].rdlen = fd_table[fd].start.dlen%128))
fd_table[fd].rdlen = fd_table[fd].start.dlen + (128L - fd_table[fd].rdlen);
else
fd_table[fd].rdlen = fd_table[fd].start.dlen;
}
if ( fd_table[fd].start.rlen == 0 )
{
fd_table[fd].rref = 0;
fd_table[fd].reof = 1;
}
else
{
FSpCreateResFile( &fd_table[fd].fs, fd_table[fd].start.fcreator, fd_table[fd].start.ftype, 0);
if ( noErr == ( err = ResError() ))
{
fd_table[fd].new = 1;
err = FSpOpenRF( &fd_table[fd].fs, fsWrPerm, &fd_table[fd].rref);
}
ExitErr(err);
if ( 0 != (fd_table[fd].rrlen = fd_table[fd].start.rlen%128))
fd_table[fd].rrlen = fd_table[fd].start.rlen + (128L - fd_table[fd].rrlen);
else
fd_table[fd].rrlen = fd_table[fd].start.rlen;
}
fd_table[fd].bstart = fd_table[fd].buffer;
}
else
{
/* header is not valid */
/* treat it (right) like a normal file */
err = OpenPlainFromMB(fd);
break;
}
}
}
else /* write data/resource fork */
{
if (fd_table[fd].blen == MIO_BUFSIZE)
{
err = fs_MBflush( fd );
if ( err > 0 ) err = 0;
ExitErr(err);
}
else
{
count = MIN( (MIO_BUFSIZE-fd_table[fd].blen), (long) n);
BlockMove( buf, fd_table[fd].bstart, (Size) count );
buf += (int) count;
fd_table[fd].blen += (int) count;
fd_table[fd].pos += count;
fd_table[fd].bstart += count;
result += (int) count;
n -= (int) count;
}
}
} /* while n */
}
ExitErr(err);
if (fd_table[fd].mode != MIO_MACBIN)
{
while (( n > 0 ) && (err == noErr))
{
if (fd_table[fd].blen == MIO_BUFSIZE)
{
count = fd_table[fd].blen;
err = FSWrite( fd_table[fd].dref, &count, fd_table[fd].buffer );
fd_table[fd].blen = 0;
fd_table[fd].bstart = fd_table[fd].buffer;
}
else
{
count = MIN( (MIO_BUFSIZE-fd_table[fd].blen), (long) n);
if (fd_table[fd].mode == MIO_ASCII)
MyBlockMove( buf, fd_table[fd].bstart, (Size) count, 0x0a, 0x0d );
else
BlockMove( buf, fd_table[fd].bstart, (Size) count );
buf += (int) count;
fd_table[fd].blen += (int) count;
fd_table[fd].pos += count;
fd_table[fd].bstart += count;
result += (int) count;
n -= (int) count;
}
} /* while n */
}
ExitErr(err);
return result;
}
static int fs_MBflush( int fd )
{
OSErr err = noErr;
long count = 0, written = 0;
char *bstart;
int result = 0;
if ( fd_table[fd].blen <= 0 )
return 0;
bstart = fd_table[fd].buffer;
fd_table[fd].bstart = fd_table[fd].buffer;
if ( fd_table[fd].deof == 0 )
{
written = fd_table[fd].pos - 128L - (long) fd_table[fd].blen;
count = ( fd_table[fd].rdlen - written );
/*
* so count is the number of df bytes still not written to file
*/
if ( count <= (long)fd_table[fd].blen )
{
fd_table[fd].blen -= (int)count;
bstart += count;
result += (int) count;
count -= (fd_table[fd].rdlen - fd_table[fd].start.dlen);
if ( count > 0 )
err = FSWrite( fd_table[fd].dref, &count, fd_table[fd].buffer );
fd_table[fd].deof = 1;
}
else
{
count = (long)fd_table[fd].blen;
fd_table[fd].blen -= (int)count;
bstart += count;
result += (int) count;
if ( (written + count) > fd_table[fd].start.dlen )
count = fd_table[fd].start.dlen - written;
if ( count > 0 )
err = FSWrite( fd_table[fd].dref, &count, fd_table[fd].buffer );
}
if ( noErr != err )
return err;
}
if ( fd_table[fd].blen <= 0 )
return result;
if ( fd_table[fd].reof == 0 )
{
written = fd_table[fd].pos - 128L - fd_table[fd].rdlen - (long)fd_table[fd].blen;
count = ( fd_table[fd].rrlen - written);
if (count <= 0)
{
/* skip clen */
fd_table[fd].pos += (long)fd_table[fd].blen;
fd_table[fd].blen = 0;
return (result + fd_table[fd].blen);
}
/*
* so count is the number of df bytes still not written to file
*/
if ( count <= fd_table[fd].blen )
{
fd_table[fd].blen -= (int)count;
result += (int) count;
count -= (fd_table[fd].rrlen - fd_table[fd].start.rlen);
if ( count > 0 )
err = FSWrite( fd_table[fd].rref, &count, bstart );
fd_table[fd].reof = 1;
}
else
{
count = (long)fd_table[fd].blen;
fd_table[fd].blen -= (int)count;
result += (int) count;
if ( (written + count) > fd_table[fd].start.rlen )
count = fd_table[fd].start.rlen - written;
if ( count > 0 )
err = FSWrite( fd_table[fd].rref, &count, bstart );
}
if ( noErr != err )
return err;
}
return result;
}
/* ejo: swap '\r' and '\n' for text files (MPW and CW). Note that we */
/* cannot use '\r' and '\n' directly, they have value 0xd and 0xa for */
/* CW and the opposite for MPW (brain damage all over) */
static int MyBlockMove( char *src, char *dst, Size n, char c1, char c2 )
{
char *tp;
for( tp = src + n ; src < tp ; src ++ )
*dst++ = ( *src == c1 ? c2 : *src );
return 0;
}
static OSErr OpenPlainFromMB( int fd )
{
OSErr err = noErr;
long count = 0;
if ( fd_table[fd].fsomode & OM_TEXT ) fd_table[fd].mode = MIO_ASCII;
else fd_table[fd].mode = MIO_BINARY;
/* macgzip -> */
if ( decompress )
{
err = MakeOFSSpec( &fd_table[fd].fs ,
fd_table[fd].mode == MIO_ASCII ? "\pSave text file:" : "\pSave binary file:" );
ofs = fd_table[fd].fs;
ExitErr(err); /* OJO */
SetMMString( "g%szip (%s) %s", decompress ? "un" : "" ,( fd_table[fd].mode == MIO_ASCII ) ? "ASCII" : "bin" , ofname );
}
/* <- macgzip */
if ( noErr != (err = FSpCreate(&fd_table[fd].fs, DefCreator, DefType, 0)))
return err;
fd_table[fd].new = 1;
if ( noErr != (err = FSpOpenDF(&fd_table[fd].fs, fsWrPerm, &fd_table[fd].dref)))
{
fd_table[fd].dref = 0;
FSpDelete(&fd_table[fd].fs);
return err;
}
count = (long)fd_table[fd].pos;
if (fd_table[fd].mode == MIO_ASCII)
MyBlockMove( (char *)&fd_table[fd].header, fd_table[fd].buffer, (Size) count, 0x0a, 0x0d );
else
BlockMove( &fd_table[fd].header, fd_table[fd].buffer, (Size) count );
fd_table[fd].blen = fd_table[fd].pos;
fd_table[fd].bstart = fd_table[fd].buffer + fd_table[fd].pos ;
return err;
}
/*******************************************************************************
*
* CatInfoToStat - fill in stat struct from CInfoPBRec struct.
*
* RETURNS: always zero.
* from stat.c, Written 4 Nov 94, Erling Johansen.
*/
/*
About this implementation
-------------------------
The stat information does not fit perfectly good for the Mac, we don't
have things like inodes, links, uid's and guids. This implementation
put the following information in the stat fields:
st_mode - S_IFDIR | 0777 for directories
- S_IFDIR | 0666 for regular files
- the w bit is cleared for locked files
- the x bit is set for applications and MPW tools
- S_IFCHR | 0777 for stdin, stdout and stderr
st_ino - ioDrDir ID for directories, file number for files
- 0 for stdin, stdout and stderr
st_dev - the volume reference number, 0 for stdin, stdout and stderr
st_nlink - always 1
st_uid - always 0
st_gid - always 0
st_size - ioFlLgLen (size of data fork)
- 0 for directories and stdin, stdout and stderr
st_atime - ioDrMdDat for dirs, ioFlMdDat for files (modification date)
- current calendar time for stdin, stdout and stderr
st_mtime - same as st_atime
st_ctime - ioDrCrDat for dirs, ioFlCrDat for files (creation date)
- current calendar time for stdin, stdout and stderr
*/
int fs_stat(FSSpec *fs, struct stat *buf)
{
CInfoPBRec info;
int err;
info.hFileInfo.ioNamePtr = fs->name;
info.hFileInfo.ioVRefNum = fs->vRefNum;
info.hFileInfo.ioFDirIndex = 0;
info.hFileInfo.ioDirID = fs->parID;
if ( noErr != ( err = PBGetCatInfo( (CInfoPBPtr) &info, false ) ) )
errno = err;
else if (buf == NULL)
errno = EFAULT;
else
return CatInfoToStat (&info, buf);
return -1;
}
static int CatInfoToStat (CInfoPBRec *info, struct stat *buf)
{
buf->st_nlink = 1;
buf->st_uid = 0;
buf->st_gid = 0;
if (info->dirInfo.ioFlAttrib & ioDirMask)
{
/* a directory */
buf->st_mode = S_IFDIR | 0777;
buf->st_ino = info->dirInfo.ioDrDirID;
buf->st_dev = info->dirInfo.ioVRefNum;
buf->st_size = 0;
buf->st_atime = info->dirInfo.ioDrMdDat;
buf->st_mtime = info->dirInfo.ioDrMdDat;
buf->st_ctime = info->dirInfo.ioDrCrDat;
}
else
{
/* a file */
buf->st_mode = S_IFREG | 0777;
if (info->hFileInfo.ioFlAttrib & 0x01)
buf->st_mode &= ~0222;
if (info->hFileInfo.ioFlFndrInfo.fdType != 'APPL'
&& info->hFileInfo.ioFlFndrInfo.fdType != 'MPST')
buf->st_mode &= ~0111;
buf->st_ino = info->hFileInfo.ioDirID;
buf->st_dev = info->hFileInfo.ioVRefNum;
buf->st_size = info->hFileInfo.ioFlLgLen;
buf->st_atime = info->hFileInfo.ioFlMdDat;
buf->st_mtime = info->hFileInfo.ioFlMdDat;
buf->st_ctime = info->hFileInfo.ioFlCrDat;
buf->st_dsize = info->hFileInfo.ioFlLgLen;
buf->st_rsize = info->hFileInfo.ioFlRLgLen;
if ( 0 != (buf->st_dsize%128))
buf->st_dsize = buf->st_dsize + ( 128 - buf->st_dsize%128 );
if ( 0 != (buf->st_rsize%128))
buf->st_rsize = buf->st_rsize + ( 128 - buf->st_rsize%128 );
buf->st_mbsize = 128 + buf->st_dsize + buf->st_rsize;
}
return 0;
}
static void SanitizeName (Str255 name)
{
int i;
for( i = 1 ; i <= name[0]; i++ )
if (( name[i] == 0x00 ) || ( name[i] == ':' ))
name[i] = '-';
if (( name[0] > 0) && (name[1] == '.'))
name[1] = '•';
}